#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;

/* word registers for retrieving values from SCI calls */
typedef struct t_tSCI32Regs
{
	DWORD	edi;
	DWORD	esi;
	DWORD	ebp;
	DWORD	reserved;
	DWORD	ebx;
	DWORD	edx;
	DWORD	ecx;
	DWORD	eax;
	
	UINT	flags;
	UINT	es;
	UINT	ds;
	UINT	fs;
	UINT	gs;
	UINT	ip;
	UINT	cs;
	UINT	sp;
	UINT	ss;
} tSCI32Regs;

typedef struct t_tSCIWordRegs
{
	WORD	di;
	WORD	filler_di;
	WORD	si;
	WORD	filler_si;
	WORD	bp;
	WORD	filler_bp;
	WORD	reserved;
	WORD	reserved1;
	WORD	bx;
	WORD	filler_bx;
	WORD	dx;
	WORD	filler_dx;
	WORD	cx;
	WORD	filler_cx;
	WORD	ax;
	WORD	filler_ax;
	
	UINT	flags;
	UINT	es;
	UINT	ds;
	UINT	fs;
	UINT	gs;
	UINT	ip;
	UINT	cs;
	UINT	sp;
	UINT	ss;
} tSCIWordRegs;

/*	byte registers for retrieving values from SCI calls	*/
typedef struct t_tSCIByteRegs
{
	BYTE	filler[16];	/*	covers edi, esi, ebp, reserved	*/
	BYTE	bl;
	BYTE	bh;
	WORD	filler1;	/*	covers high 16 bits	*/
	BYTE	dl;
	BYTE	dh;
	WORD	filler2;	/*	covers high 16 bits	*/
	BYTE	cl;
	BYTE	ch;
	WORD	filler3;	/*	covers high 16 bits	*/
	BYTE	al;
	BYTE	ah;
	WORD filler4[9];	/*	covers flags, es, ..., etc.	*/
} tSCIByteRegs;

/*
* general purpose registers union -
* overlays the corresponding word and byte registers.
*/
typedef union t_tSCIRegisters
{
	tSCI32Regs		d;
	tSCIWordRegs	w;
	tSCIByteRegs	b;
} tSCIRegisters;
class TSCI
{
	static TSCI self_;
	HINSTANCE tsci_;
	TSCI():tsci_(0){}
public:
	static TSCI& get_instance(){
		if(self_.tsci_ == 0){
			char lpSystem[MAX_PATH];
			GetSystemDirectory( lpSystem, MAX_PATH );
			char     lpLibFileNameS[MAX_PATH];
			sprintf(lpLibFileNameS,"%s\\TSCI.DLL",lpSystem);
			self_.tsci_ = LoadLibrary(lpLibFileNameS);
		}
		return self_;
	}
	BOOL get(tSCIRegisters *prRegs )
	{
		typedef BOOL (WINAPI * DTSCIGetWithOpenIF)(tSCIRegisters *prRegs );
		DTSCIGetWithOpenIF       TSCIGetWithOpenIF;
		TSCIGetWithOpenIF =(DTSCIGetWithOpenIF)GetProcAddress(self_.tsci_,"TSCIGetWithOpenIF");
		if( TSCIGetWithOpenIF == NULL )
		{
			return(FALSE);                             
		}
		else                                           
			return(TSCIGetWithOpenIF(prRegs));         
	}
	BOOL set(tSCIRegisters *prRegs )
	{
		typedef BOOL (WINAPI * DTSCIGetWithOpenIF)(tSCIRegisters *prRegs );
		DTSCIGetWithOpenIF       TSCIGetWithOpenIF;
		TSCIGetWithOpenIF =(DTSCIGetWithOpenIF)GetProcAddress(self_.tsci_,"TSCISetWithOpenIF");
		if( TSCIGetWithOpenIF == NULL )
		{
			return(FALSE);                             
		}
		else                                           
			return(TSCIGetWithOpenIF(prRegs));         
	}
	~TSCI(){
		if(self_.tsci_ != 0){
			::FreeLibrary(self_.tsci_);
		}
	}
};
TSCI TSCI::self_;
#define SCI_ATA_PRIORITY			(WORD) 0x0126
void print(tSCIWordRegs* reg)
{
	cout << showbase << hex 
		<< "di = " << reg->di 
		<< "; si[default] = " << reg->si 
		<< "; ax = " << reg->ax 
		<< "; bx = " << reg->bx 
		<< "; cx[current] = " << reg->cx 
		<< "; dx[number]= " << reg->dx
		<< endl;
}
class HddPriority
{
	vector<string> items_;
	int num_ ;
public:
	HddPriority():num_(get_pattern_num()){
		for(int i = 1; i <= num_; ++i){
			WORD pt = get_pattern(i);
			items_.push_back(get_item(pt));
		}
	}
	BOOL Write(int selected)
	{
		if(selected <= 0 && selected > num_)
			return FALSE;
		WORD pattern = get_pattern(selected);
		if(pattern){
			tSCIRegisters  rSCIRegs;
			init_regs(rSCIRegs);
			rSCIRegs.w.cx = pattern;
			if(TSCI::get_instance().set(&rSCIRegs)){
				return TRUE;
			}
		}
		return false;
	}

private:

	void init_regs(tSCIRegisters& regs)const
	{
		memset(&regs, 0, sizeof(regs));
		regs.w.ax = 0x44f3;
		regs.w.bx = SCI_ATA_PRIORITY;	// 0x0126
	}

	WORD get_default_pattern()const
	{
		tSCIRegisters  rSCIRegs;
		init_regs(rSCIRegs);
		rSCIRegs.w.cx = 0x0000;
		if(TSCI::get_instance().get(&rSCIRegs)){
			return rSCIRegs.w.si;
		}
		return 0;
	}
	WORD get_current_pattern()const
	{
		tSCIRegisters  rSCIRegs;
		init_regs(rSCIRegs);
		rSCIRegs.w.cx = 0x0000;
		if(TSCI::get_instance().get(&rSCIRegs)){
			return rSCIRegs.w.cx;
		}
		return 0;
	}
	WORD get_pattern(int index)const
	{
		tSCIRegisters  rSCIRegs;
		init_regs(rSCIRegs);
		rSCIRegs.w.cx = index;
		if(TSCI::get_instance().get(&rSCIRegs)){
			return rSCIRegs.w.cx;
		}
		return 0;
	}
	int get_pattern_num()const
	{
		tSCIRegisters  rSCIRegs;
		init_regs(rSCIRegs);
		rSCIRegs.w.cx = 0x0000;
		if(TSCI::get_instance().get(&rSCIRegs)){
			return rSCIRegs.w.dx;
		}
		return 0;
	}

	string get_item(WORD BitPattern)const
	{
		if(BitPattern == 0)
		{
			return "Error";
		}
		WORD mask = (WORD)0x000F;
		string str;
		for(int i = 12; i > 0; i-=4){
			WORD w = static_cast<WORD>(BitPattern >> i) & mask;
			switch(w){
			case 0x0000:
				str += "[Built-in HDD] ";
				break;
			case 0x0004:
				str+= "[Built-in 2 HDD] ";
				break;
			case 0x0005:
				str += "[USB Memory] ";
			default:
				;
				//str += "Unkonw Device -> ";
			}
		}
		return str;
	}
	friend ostream& operator<<(ostream& os, const HddPriority&);
};
ostream& operator<<(ostream& os, const HddPriority& hp)
{
	//std::copy(hp.items_.begin(), hp.items_.end(), ostream_iterator<string>(os, "\n"));
	typedef vector<string>::const_iterator CI;
	CI end = hp.items_.end();
	int i = 1;
	for(CI it = hp.items_.begin(); it != end; ++it, ++i){
		os << i << " : " << *it << endl;		
	}
	os<< endl;
	os<< "Default: " << hp.get_item(hp.get_default_pattern()) << endl;
	os<< "Current: " << hp.get_item(hp.get_current_pattern()) << endl;
	return os;
}

int main()
{
	HddPriority hp;
	cout << hp;
	int select;
	cout << "Please select:" << endl;
	while(cin >> select){
		if(hp.Write(select)){
			cout <<" Setup successfully! :)" <<endl;
		}
		else{
			cout << "Fail ! :(" << endl;
		}
		cout << hp;
		cout << "Please select:" << endl;
	}
	return 0;	
}